/*

银行取款系统
在这个例子中，多个客户线程尝试从同一个银行账户中取款。
银行账户的余额是一个共享资源，因此需要用互斥锁来保护，以防止多个线程同时访问导致的数据竞争。
同时，我们使用一个无名信号量来模拟银行柜员的数量限制，即同一时间最多只能有几个客户同时进行取款操作。

顾客
    当信号量没有轮到你的时候 不能运行
    并且 需要判断 银行余额是否有 互斥锁 还需要判断余额是否小于 0 

        取钱
        存钱
    释放信号量
    释放锁

柜员
    一次性只能接待 1



*/
#include <head.h>

// 信号量
sem_t sem_counter; // 柜台信号量

// 互斥锁
pthread_mutex_t mutex_balance; // 余额锁

// 线程
#define Cou_T 3  // 柜员数量
#define Cli_T 20 // 用户数量

pthread_t Tid_Counter[Cou_T]; // 柜台线程
pthread_t Tid_Client[Cli_T];  // 用户线程

//int Cou_Func_ID[Cou_T]; // 柜台 线程 函数 ID
pthread_t Cli_Func_ID[Cli_T]; // 用户 线程 函数 ID

// 银行 余额
int balance = 1050;

//void *func_Counter(void * val); // 柜员线程
void *func_Client(void * val);  // 用户线程

int main(int argc, char const *argv[])
{
    // 初始化 互斥锁
    pthread_mutex_init(&mutex_balance, NULL);
    // 初始化 信号量
    sem_init(&sem_counter, 0, Cou_T);

    // // 创建线程
    // /*柜台线程 创建*/
    // for (size_t i = 0; i < Cou_T; i++)
    // {
    //     Cou_Func_ID[i] = i + 1; // 初始化 线程 函数 号
    //     pthread_create(&Tid_Counter[i], NULL, func_Counter, (void *)&Cou_Func_ID[i]);
    // }
    sleep(1);
    /*顾客线程 创建*/
    for (size_t i = 0; i < Cli_T; i++)
    {
        Cli_Func_ID[i] = i + 1; // 初始化 线程 函数 号
        pthread_create(&Tid_Client[i], NULL, func_Client, (void *)&Cli_Func_ID[i]);
    }

    // 回收线程
    /*柜台线程 回收*/
    for (size_t i = 0; i < Cou_T; i++)
    {
        pthread_join(Tid_Counter[i], NULL);
    }
    /*柜台线程 回收*/
    for (size_t i = 0; i < Cli_T; i++)
    {
        pthread_join( Tid_Client[i], NULL);
    }
    // 销毁 互斥锁 余额锁
    pthread_mutex_destroy( &mutex_balance );

    // 销毁 信号量 
    sem_destroy(&sem_counter);

    return 0;
}

void *func_Counter(void *val) // 柜员线程
{
    printf("嗨喽 你是存钱 还是办信用卡\n");
    printf("取钱出门左拐 \n");
    return NULL;
}

void *func_Client(void *val)  // 用户线程
{
    printf("线程 %d 正在排队\n" ,  *((int * )val) );
    sleep(1);
    // 信号量 P 操作 等待
    sem_wait(&sem_counter);
    printf("线程 %d 进入柜台\n" , *((int * )val) );
    // 互斥锁 保护余额
    pthread_mutex_lock(&mutex_balance);
    // 用户操作
    printf("======================================================================\n");
    printf("线程%d  取钱\n" , *((int * )val) );
    printf("开始取钱.....\n");

    balance = balance - 50;

    printf("线程 %d 取了 %d 元\n" , *((int * )val) , 50);

    printf("系统:当前余额 %d \n" , balance);
    sleep(3);
    printf("取钱结束\n");
    printf("======================================================================\n");
    // 释放锁
    pthread_mutex_unlock(&mutex_balance);
    sleep(1);
    // 信号量 V操作
    sem_post(&sem_counter);
    

    return NULL;

}
